package co.gov.medellin.sdep.sisdep.model.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.jdbc.object.SqlUpdate;

import co.gov.medellin.sdep.sisdep.common.OracleHelper;
import co.gov.medellin.sdep.sisdep.common.dto.GenericComponentVO;
import co.gov.medellin.sdep.sisdep.common.dto.GenericComponentValueVO;
import co.gov.medellin.sdep.sisdep.common.dto.ValueObjectDTO;

/**
 * @author Usuario
 *
 */
public class ValueObjectDAOImpl extends JdbcDaoSupport implements IValueObjectDAO {

	/**
	 * 
	 */
	public ValueObjectDAOImpl() {
	}

    //------------------------------------------------------------
    //--- Implementacion de DAO para MasterList
    //------------------------------------------------------------

	/** */
    private GetGenericComponents getGenericComponents;
    /** */
    private LoadTypeMasterList loadTypeMasterList;
    /** */
    private UpdateTypeMasterList updateTypeMasterList;
    /** */
    private SaveTypeMasterList saveTypeMasterList;
    /** */
    private LoadTypeValueMasterList loadTypeValueMasterList;
    /** */
    private UpdateTypeValueMasterList updateTypeValueMasterList; 
    /** */
    private SaveTypeValueMasterList saveTypeValueMasterList;
    
    /** Finders para los objetos tipo y valor tipo: **/
    private FindTypeByPrimaryKeyQuery findTypeByPrimaryKeyQuery;
    private FindTypeValueByPrimaryKeyQuery findTypeValueByPrimaryKeyQuery;
    private FindTypeValueByCodeQuery findTypeValueByCodeQuery;
    
	
	public List getGenericComponents() throws DataAccessException{
		return getGenericComponents.runQuery();
	}
	
	public List loadTypeMasterList(GenericComponentVO genCompVO){
		return loadTypeMasterList.runQuery(genCompVO);
	}
	
	public void updateTypeMasterList(GenericComponentVO genCompVO){
		updateTypeMasterList.execute(genCompVO);
	}

	public void saveTypeMasterList(GenericComponentVO genCompVO){
		saveTypeMasterList.execute(genCompVO);
	}

	public List loadTypeValueMasterList(GenericComponentValueVO gcvSearchVO){
		return loadTypeValueMasterList.runQuery(gcvSearchVO);
	}
	
	public void updateTypeValueMasterList(GenericComponentValueVO gcvVO){
		updateTypeValueMasterList.execute(gcvVO);
	}

	public void saveTypeValueMasterList(GenericComponentValueVO gcvVO){
		saveTypeValueMasterList.execute(gcvVO);
	}

	/**
	 * 
	 * Metodo que permite consultar un objeto Valor Tipo usando su ID.
	 * @author carlos.perez@consult-soft.com  18-04-2012 
	 * @param id
	 */
	public GenericComponentVO findTypeByPrimaryKey(long idType) {
		return findTypeByPrimaryKeyQuery.runQuery(idType);
	}
	
	/**
	 * 
	 * Metodo que permite consultar un objeto Valor Tipo usando su ID.
	 * @author carlos.perez@consult-soft.com  18-04-2012 
	 * @param id
	 */
	public GenericComponentValueVO findTypeValueByPrimaryKey(long idTypeValue) {
		return findTypeValueByPrimaryKeyQuery.runQuery(idTypeValue);
	}

	/**
	 * 
	 * Metodo que permite consultar un objeto Valor Tipo usando el Id del Tipo y su Codigo 
	 * (en base de datos corresponde al Valor).
	 * 
	 * @author carlos.perez@consult-soft.com  
	 * @version 19-06-2012
	 * 
	 * @param idType
	 * @param typeValueCode
	 * 
	 */
	public GenericComponentValueVO findTypeValueByCode(String idType, String typeValueCode) {
		return findTypeValueByCodeQuery.runQuery(idType, typeValueCode);
	}	
	
    /**
     * metodo de inicializacion de operaciones DAO
     */
    public void initDao() {
	   getGenericComponents = new GetGenericComponents ( getDataSource() );
	   loadTypeMasterList = new LoadTypeMasterList ( getDataSource() );
	   updateTypeMasterList = new UpdateTypeMasterList ( getDataSource() );
	   saveTypeMasterList = new SaveTypeMasterList ( getDataSource() );
	   loadTypeValueMasterList = new LoadTypeValueMasterList ( getDataSource() );
	   updateTypeValueMasterList = new UpdateTypeValueMasterList ( getDataSource() ); 
	   saveTypeValueMasterList = new SaveTypeValueMasterList ( getDataSource() );
	   findTypeByPrimaryKeyQuery = new FindTypeByPrimaryKeyQuery ( getDataSource() );
	   findTypeValueByPrimaryKeyQuery = new FindTypeValueByPrimaryKeyQuery ( getDataSource() );
	   findTypeValueByCodeQuery = new FindTypeValueByCodeQuery(getDataSource());
    }
	    
	    // --------------------------------------------------------------------
	    // --- implementacion de la persistencia
	    // --------------------------------------------------------------------
	    
	    // ------------- BaseQueryOperationValorTipo --------------------------

	    abstract class BaseQueryOperationValorTipo extends MappingSqlQuery	{
		
			public BaseQueryOperationValorTipo(DataSource ds,String sql) {
		   		super(ds,sql);
			}
			
			protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
				ValueObjectDTO valueObjectDTO = new ValueObjectDTO();
				valueObjectDTO.setIdTipo(rs.getLong("ID_TIPO"));
				valueObjectDTO.setTipNombre(rs.getString("TIP_NOMBRE"));
				valueObjectDTO.setIdValorTipo(rs.getLong("ID_VALOR_TIPO"));
				valueObjectDTO.setVrtNombre(rs.getString("VRT_NOMBRE"));
				return valueObjectDTO;
			}
	    }
	    
	    // ------------- BaseQueryOperationTipo -------------------------------

	    abstract class BaseQueryOperationTipo extends MappingSqlQuery	{
			
			public BaseQueryOperationTipo(DataSource ds,String sql) {
		   		super(ds,sql);
			}	
			
			protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
				GenericComponentVO gcVO = new GenericComponentVO(false);
				gcVO.setComponentId(rs.getString("ID_TIPO"));
				gcVO.setComponentKey(rs.getString("TIP_NOMBRE"));
				gcVO.setComponentDescription(rs.getString("TIP_DESCRIPCION"));
				gcVO.setIdCreateUser(rs.getString("TIP_USUARIO_CREA"));				
				gcVO.setCreateDate(OracleHelper.timeStamp2string(rs.getTimestamp("TIP_FECHA_CREA")));
				gcVO.setIdModifyUser(rs.getString("TIP_USUARIO_MODIFICA"));
				gcVO.setModifyDate(OracleHelper.timeStamp2string(rs.getTimestamp("TIP_FECHA_MODIFICA"))); 
				return gcVO;
			}
	    }

	    // ------------- BaseQueryOperationTipoMaestra ------------------------

	    abstract class BaseQueryOperationTipoMaestra extends MappingSqlQuery	{
			
			public BaseQueryOperationTipoMaestra(DataSource ds,String sql) {
		   		super(ds,sql);
			}	
		
			protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
				GenericComponentValueVO gcVO = new GenericComponentValueVO();
				gcVO.setComponentValueId(rs.getString("ID_VALOR_TIPO"));
				gcVO.setComponentId(rs.getString("ID_TIPO"));
				gcVO.setComponentValueName(rs.getString("VRT_NOMBRE"));
				gcVO.setComponentValueKey(rs.getString("VRT_VALOR"));
				gcVO.setComponentValueDesc(rs.getString("VRT_DESCRIPCION"));
				gcVO.setIdCreateUser(rs.getString("VRT_USUARIO_CREA"));
				gcVO.setCreateDate(OracleHelper.timeStamp2string(rs.getTimestamp("VRT_FECHA_CREA")));
				gcVO.setIdModifyUser(rs.getString("VRT_USUARIO_MODIFICA"));
				gcVO.setModifyDate(OracleHelper.timeStamp2string(rs.getTimestamp("VRT_FECHA_MODIFICA"))); 
                return gcVO;
			}
	    }		
	    // ------------- GetGenericComponents ---------------------------------
		
		/**
		 * Obtiene el mapa que contiene los datos asociados a cada uno de los
		 * componentes genericos de BCOPO.
		 * 
		 * @return HashMap Mapa con las listas de los componentes genericos y sus
		 *         valores asociados.
		 * @throws SQLException
		 */
	    class GetGenericComponents extends BaseQueryOperationValorTipo {
	    	private static final String SQL = 
	    	"SELECT " +
	    	"	TM.ID_TIPO, " +
	    	"	TM.TIP_NOMBRE, " +
	    	"	VTM.ID_VALOR_TIPO, " +
	    	"	VTM.VRT_NOMBRE " + 
			"FROM " +
			"	ADM_TIPO_MAESTRA_T TM, ADM_VALOR_TIPO_MAESTRA_T VTM " +
			"WHERE " +
			"	TM.ID_TIPO = VTM.ID_TIPO " +
			"ORDER BY " +
			"	TM.TIP_NOMBRE, " +
			"	VTM.VRT_NOMBRE ASC";
	    	
	    	public GetGenericComponents(DataSource ds) {
	    		super(ds,SQL);
				compile();
	    	}
	    	    	
	    	public List runQuery() {
	    		List result =  execute();
				if ( result != null && result.size()>0 ) {	        		
					return result;					
	        	} else {
	        		return null;
	        	}
	    	}
	    }
	    
	    // ------------- LoadTypeMasterList ----------------------------------
		
	    /**
		 * Metodo que permite obtener el listado de Tipos definidos en el sistema. Es posible
		 * buscar por parte del nombre del tipo. Para obternerlos todos se una el % en como
		 * valor del parametro de la consulta.
		 *  
		 * @author carlos.perez@consult-soft.com  03-02-2012
		 * @param genCompVO
		 * @return
		 * @throws SISDEPException
		 */
	    class LoadTypeMasterList extends BaseQueryOperationTipo {
		private static final String SQL = "SELECT * FROM ADM_TIPO_MAESTRA_T "
				+ "WHERE UPPER(TIP_NOMBRE) LIKE ? " + "ORDER BY TIP_NOMBRE ASC";
	    	
	    	public LoadTypeMasterList(DataSource ds) {
	    		super(ds,SQL);
	      		declareParameter( new SqlParameter(Types.CHAR) ); 
				compile();
	    	}
	    	    	
	    	public List runQuery(GenericComponentVO genCompVO) {
				List result =  execute( new Object[]{new String("%" + genCompVO.getComponentKey().toUpperCase() + "%")});
				if ( result != null && result.size() > 0 ) {
	        		return result;
	        	} else {
	        		return null;
	        	}	
	    	}
	    }

    // ------------- UpdateTypeMasterList ----------------------------------
		
		/**
		 * Metodo que permite la actualizacion de los datos un TIPO en la lista maestra.
		 * @author carlos.perez@consult-soft.com  06-02-2012 
		 * @param genCompVO
		 * @throws SISDEPException
		 */
		class UpdateTypeMasterList extends SqlUpdate	{

			private static final String SQL = "UPDATE ADM_TIPO_MAESTRA_T SET "
				+ "TIP_NOMBRE = ?, "
				+ "TIP_DESCRIPCION = ?, "
				+ "TIP_USUARIO_MODIFICA = ?, "
				+ "TIP_FECHA_MODIFICA = SYSDATE WHERE ID_TIPO = ? ";
		
			public  UpdateTypeMasterList(DataSource ds) {
				super(ds,SQL);
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				compile();
			}
		
			public void execute(GenericComponentVO genCompVO) {
				//int rowcount = 
				UpdateTypeMasterList.this.update( new Object[]{
						genCompVO.getComponentKey(),
					    genCompVO.getComponentDescription(),
					    genCompVO.getLoggedUserId(),
					    genCompVO.getComponentId()
					});
				//if (rowcount != 1) {
					/*
					//String[] args = {genCompVO.getComponentKey()};					
					//throw new BCOPOException("ERROR - No fue posible actualizar el registro asociado al " +
					//		"TIPO: [%s] de la Lista Maestra.", "TIPO_LISTA_MAESTRA", args);
					Object [] infoError = {genCompVO.getComponentKey(),new Long(rowcount)};
					throw new ValueObjectRuntimeException(new ValueObjectMessageDescriptor(MessageDescriptorConstant.NO_RECORDS_UPDATED), infoError, null);
				*/			
				//}
			}
	    }
	    
	    // ------------- SaveTypeMasterList ----------------------------------
	    
		/**
		 * Metodo que permite la insercion de los datos de un nuevo TIPO en la lista maestra.
		 * @author carlos.perez@consult-soft.com  06-02-2012 
		 * @param genCompVO
		 * @throws SISDEPException
		 */
		class SaveTypeMasterList extends SqlUpdate	{
			
			private static final String SQL = ""
			+ "INSERT INTO ADM_TIPO_MAESTRA_T "
			+ "(ID_TIPO, TIP_NOMBRE, TIP_DESCRIPCION, TIP_USUARIO_CREA, "
			+ "TIP_FECHA_CREA) "
		    + "VALUES (ADM_TIPO_MAESTRA_SEC.nextVal, ?, ?, ?, SYSDATE) ";
		    
			public  SaveTypeMasterList(DataSource ds) {
				super(ds,SQL);
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				compile();
			}
			
			public void execute(GenericComponentVO genCompVO) {
				//int rowcount = 
					SaveTypeMasterList.this.update( new Object[]{
						genCompVO.getComponentKey(), 
					    genCompVO.getComponentDescription(),
					    genCompVO.getLoggedUserId()
					});
				//if (rowcount != 1) {
					/*
					//String[] args = {genCompVO.getComponentKey()};
					//throw new DigitalDirectoryException("ERROR - No fue posible insertar el registro asociado a la " +
					//		"TIPO: [%s] de la Lista Maestra.", "TIPO_LISTA_MAESTRA", args);
				Object [] infoError = {propietarioVehiculo.getIdpropietario() + " - " + propietarioVehiculo.getIdvehiculo()};
				throw new PropietarioVehiculoRuntimeException(new PropietarioVehiculoMessageDescriptor(MessageDescriptorConstant.SAVE), infoError, e);
				*/				
				//}
			}	
		}
		
	    // ------------- LoadTypeValueMasterList ----------------------------------
		
	    /**
		 * Metodo que permite obtener el listado de Valores para un Tipo definido en el sistema. Es posible
		 * buscar por parte del nombre del valor tipo. Para obternerlos todos se una el % en como
		 * valor del parametro de la consulta.
		 *  
		 * @author carlos.perez@consult-soft.com  07-02-2012
		 * @param genCompVO
		 * @return
		 * @throws SISDEPException
		 */
		class LoadTypeValueMasterList extends BaseQueryOperationTipoMaestra {
			private static final String SQL = "SELECT * FROM " 
				+ "ADM_VALOR_TIPO_MAESTRA_T "
				+ "WHERE ID_TIPO = ? AND UPPER(VRT_NOMBRE) LIKE ? "
				+ "ORDER BY VRT_NOMBRE ASC";
	    	
	    	public LoadTypeValueMasterList(DataSource ds) {
	    		super(ds,SQL);
	      		declareParameter( new SqlParameter(Types.CHAR) );
	      		declareParameter( new SqlParameter(Types.CHAR) );
				compile();
	    	}
	    	    	
	    	public List runQuery(GenericComponentValueVO gcvSearchVO) {
				List result =  execute( new Object[]{
			      		gcvSearchVO.getComponentId(),
			       		"%" + gcvSearchVO.getComponentValueName().toUpperCase() + "%"
						});    		
				if ( result != null && result.size()>0 ) {
	        		return result;
	        	} else {
	        		return null;
	        	}
	    	}
	    }
	    
    // ------------- UpdateTypeValueMasterList ----------------------------------
		
		/**
		 * Metodo que permite la actualizacion de los datos un VALOR TIPO en la lista maestra.
		 * @author carlos.perez@consult-soft.com  07-02-2012 
		 * @param genCompVO
		 * @throws SISDEPException
		 */
		class UpdateTypeValueMasterList extends SqlUpdate	{

	    	private static final String SQL = "UPDATE ADM_VALOR_TIPO_MAESTRA_T SET "
	    		+ "ID_TIPO = ?, "
	    		+ "VRT_NOMBRE = ?, "
	    		+ "VRT_VALOR = ?, "
	    		+ "VRT_DESCRIPCION = ?, "
				+ "VRT_USUARIO_MODIFICA = ?, "
				+ "VRT_FECHA_MODIFICA = SYSDATE "
				+ "WHERE "
				+ "ID_VALOR_TIPO = ? ";
		
			public  UpdateTypeValueMasterList(DataSource ds) {
				super(ds,SQL);
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				compile();
			}
		
			public void execute(GenericComponentValueVO gcvVO) {
				//int rowcount = 
					UpdateTypeValueMasterList.this.update( new Object[]{					
						gcvVO.getComponentId(),
						gcvVO.getComponentValueName(),
						gcvVO.getComponentValueKey(),
					    gcvVO.getComponentValueDesc(),
					    gcvVO.getLoggedUserId(),
					    gcvVO.getComponentValueId()
					});
				//if (rowcount != 1) {
					//String[] args = {gcvVO.getComponentValueName()};
					//throw new BCOPOException("ERROR - No fue posible actualizar el registro asociado al " +
					//		"VALOR TIPO: [%s] de la Lista Maestra.", "VALOR_TIPO_LISTA_MAESTRA", args);
				//}
				
			}
		
	    }

	    // ------------- SaveTypeValueMasterList ----------------------------------
	    
		/**
		 * Metodo que permite la insercion de los datos de un nuevo VALOR TIPO en la lista maestra.
		 * @author carlos.perez@consult-soft.com  07-02-2012 
		 * @param genCompVO
		 * @throws SISDEPException
		 */
		class SaveTypeValueMasterList extends SqlUpdate	{
			
			private static final String sql = "INSERT INTO ADM_VALOR_TIPO_MAESTRA_T "
				+ "(ID_VALOR_TIPO, ID_TIPO, VRT_NOMBRE, VRT_VALOR, VRT_DESCRIPCION, "
				+ "VRT_USUARIO_CREA, VRT_FECHA_CREA) "
				+ "VALUES (ADM_VALOR_TIPO_MAESTRA_SEC.nextVal, ?, ?, ?, ?, ?, SYSDATE) ";
			
			public  SaveTypeValueMasterList(DataSource ds) {
				super(ds,sql);
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				declareParameter( new SqlParameter(Types.CHAR) );
				compile();
			}
			
			public void execute(GenericComponentValueVO gcvVO) {
				//int rowcount = 
					SaveTypeValueMasterList.this.update( new Object[]{
						gcvVO.getComponentId(),
						gcvVO.getComponentValueName(),
						gcvVO.getComponentValueKey(),
					    gcvVO.getComponentValueDesc(),
					    gcvVO.getLoggedUserId()
					});
				//if (rowcount != 1) {
				/*
					//String[] args = {gcvVO.getComponentValueName()};					
					//throw new DigitalDirectoryException("ERROR - No fue posible insertar el registro asociado al " +
					//		"VALOR TIPO: [%s] de la Lista Maestra.", "VALOR_TIPO_LISTA_MAESTRA", args);
				Object [] infoError = {propietarioVehiculo.getIdpropietario() + " - " + propietarioVehiculo.getIdvehiculo()};
				throw new PropietarioVehiculoRuntimeException(new PropietarioVehiculoMessageDescriptor(MessageDescriptorConstant.SAVE), infoError, e);
				*/
				//}				
			}	
		}
		
	    // ------------- FindTypeByPrimaryKeyQuery -------------------------------
	    class FindTypeByPrimaryKeyQuery extends BaseQueryOperationTipo {
			private static final String SQL = "SELECT * FROM ADM_TIPO_MAESTRA_T WHERE ID_TIPO = ? ";
	    	public FindTypeByPrimaryKeyQuery(DataSource ds) {
	    		super(ds,SQL);
				declareParameter( new SqlParameter(Types.INTEGER) );
				compile();
	    	}
	    	public GenericComponentVO runQuery(long id) {
				List result =  execute( new Object[]{new Long(id)});
				if ( result.size() > 0 ) {
	        		return (GenericComponentVO) result.get(0);
	        	} else {
	        		return null;
	        	}
	    	}
	    }

	    // ------------- FindTypeValueByPrimaryKeyQuery -------------------------------
	    class FindTypeValueByPrimaryKeyQuery extends BaseQueryOperationTipoMaestra {
			private static final String SQL = "SELECT * FROM ADM_VALOR_TIPO_MAESTRA_T WHERE ID_VALOR_TIPO = ? ";
	    	public FindTypeValueByPrimaryKeyQuery(DataSource ds) {
	    		super(ds,SQL);
				declareParameter( new SqlParameter(Types.INTEGER) );
				compile();
	    	}
	    	public GenericComponentValueVO runQuery(long id) {
				List result =  execute( new Object[]{new Long(id)});
				if ( result.size() > 0 ) {
	        		return (GenericComponentValueVO) result.get(0);
	        	} else {
	        		return null;
	        	}
	    	}
	    }
	    // ------------- FindTypeValueByCodeQuery -------------------------------
	    class FindTypeValueByCodeQuery extends BaseQueryOperationTipoMaestra {
			private static final String SQL = 
				"SELECT * FROM ADM_VALOR_TIPO_MAESTRA_T "
				+ "WHERE ID_TIPO = ? AND ID_VALOR_TIPO = ? ";
			
	    	public FindTypeValueByCodeQuery(DataSource ds) {
	    		super(ds,SQL);
				declareParameter(new SqlParameter(Types.CHAR));
				declareParameter(new SqlParameter(Types.CHAR));
				compile();
	    	}
	    	public GenericComponentValueVO runQuery(String idType, String typeValueCode) {
				List result =  execute( new Object[]{idType, typeValueCode});
				if ( result.size() > 0 ) {
	        		return (GenericComponentValueVO) result.get(0);
	        	} else {
	        		return null;
	        	}
	    	}
	    }
}
